package com.zqx.strategy.client;

import ch.qos.logback.classic.spi.EventArgUtil;
import org.apache.commons.io.FileUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.net.URLDecoder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@RestController
public class DownloadClient {

    private final static long per_page=1024L*1024L*50L;
    private final static String DOWN_PATH="F:\\fileItem";
    ExecutorService pool=Executors.newFixedThreadPool(10);

    //需要知道文件大小 和 文件名称
    //使用探测获取文件信息 然后使用多线程分片下载 最后一个分片下载完 开始合并
    @RequestMapping("/downloadFile")
    public String downloadFile() throws Exception{
        FileInfo fileInfo = download(0, 10, -1, null);
        if (fileInfo!=null){
            int pages=(int)Math.ceil(fileInfo.fSize/per_page)+1;
            for (int i = 0; i < pages; i++) {
                pool.submit(new DownLoad(i*per_page,(i+1)*per_page-1,i,fileInfo.fName));
            }
        }
        return "success";
    }

    //分片大小=结束位置-开始位置
    //临时存储文件
    /**
     * 下载文件
     * @param start 开始位置
     * @param end 结束位置
     * @param page 分片
     * @param fName 文件名称
     * @return
     */
    private FileInfo download(long start,long end,long page,String fName) throws Exception{
        try {
            //断点下载 需要探测
            //
            File file = new File(DOWN_PATH, page + "-" + fName);
            //page=-1表示探
            //当文件不是探测情况 并且不是损坏的情况才可以进行断点下载
            if (file.exists()
                    && page!=-1
                    && file.length() == per_page) {
                return null;
            }
            CloseableHttpClient client = HttpClients.createDefault();
            HttpGet httpGet = new HttpGet("http://127.0.0.1:8080/download");
            httpGet.setHeader("Range","bytes="+start+"-"+end);
            HttpResponse response = client.execute(httpGet);
            String fSize = response.getFirstHeader("fSize").getValue();
            fName = URLDecoder.decode(response.getFirstHeader("fName").getValue(),"utf-8");

            HttpEntity entity = response.getEntity();
            InputStream is = entity.getContent();
            FileOutputStream fos = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int ch;
            while ((ch = is.read(buffer)) != -1) {
                fos.write(buffer,0,ch);
            }
            is.close();
            fos.flush();
            fos.close();
            if (end-Long.valueOf(fSize)>0) {
                mergeFile(fName,page);
            }
            return new FileInfo(Long.valueOf(fSize),fName);
        } catch (IOException e) {
            System.out.println("请求异常");
            //e.printStackTrace();
        }

        return null;
    }

    private void mergeFile(String fName,long page) throws Exception{
        try {
            File file = new File(DOWN_PATH, fName);
            BufferedOutputStream os=new BufferedOutputStream(new FileOutputStream(file));

            for (int i = 0; i <= page; i++) {
                File temFile = new File(DOWN_PATH,i+"-"+fName);
                while (!file.exists() || (i != page && temFile.length() < per_page)) {
                    Thread.sleep(100);
                }
                byte[] bytes = FileUtils.readFileToByteArray(temFile);
                os.write(bytes);
                os.flush();
                temFile.delete();
            }
            File file1 = new File(DOWN_PATH, -1 + "-null");
            file1.delete();
            os.flush();
            os.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    class DownLoad implements Runnable{

        private long start,end,page;
        private String fName;

        public DownLoad(long start, long end, long page, String fName) {
            this.start = start;
            this.end = end;
            this.page = page;
            this.fName = fName;
        }

        @Override
        public void run() {
            try {
                download(start,end,page,fName);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    class FileInfo{
        long fSize;
        String fName;

        public FileInfo(long fSize, String fName) {
            this.fSize = fSize;
            this.fName = fName;
        }
    }
}